package com.eairlv.route.agent.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.eairlv.route.agent.entity.AuthenticationVO;
import com.eairlv.route.agent.entity.HttpResult;
import com.eairlv.route.agent.entity.Result;
import com.eairlv.route.agent.utils.LogUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.concurrent.ScheduledFuture;

/**
 * @author eairlv
 * @description
 * @date 11:33 2019/10/25
 */
@Slf4j
@Service
public class AuthenticationService {

    public static final long UPDATE_INTERVAL_NONE = 0L;

    public static final int UNIX_TIME_LENGTH = 13;

    public static final String URL_DELIMITER = "/";

    @Autowired
    AuthenticationProperties authenticationProperties;

    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;

    @Autowired
    RestTemplate restTemplate;

    @Value("${route.agent.url:http://localhost:12112/route/server/authentication}")
    String url;

    @Value("${route.agent.session}")
    String session;

    /**
     * 加载远程配置
     */
    public void loadProperties(){
        String result = restTemplate.getForObject(url + URL_DELIMITER + session, String.class);
        TypeReference<Result<AuthenticationVO>> typeReference = new TypeReference<Result<AuthenticationVO>>(){};
        Result<AuthenticationVO> authenticationVOResult = JSON.parseObject(result, typeReference);
        if (authenticationVOResult != null
                && authenticationVOResult.getCode() == HttpResult.SUCCESS.getCode()){
            log.info("loadProperties data: {}", JSON.toJSONString(authenticationVOResult.getData()));
            authenticationProperties.setAesKey(authenticationVOResult.getData().getAesKey());
            authenticationProperties.setIgnore(authenticationVOResult.getData().getIgnoreUri());
            authenticationProperties.setExpire(authenticationVOResult.getData().getExpire());
            if (authenticationVOResult.getData().getUpdateInterval() != UPDATE_INTERVAL_NONE){
                log.info("next update at {} ms later", authenticationVOResult.getData().getUpdateInterval());
                threadPoolTaskScheduler.scheduleWithFixedDelay(this::loadProperties, authenticationVOResult.getData().getUpdateInterval());
            }
        }
    }

    /**
     * 检验token
     * @param token
     * @return
     */
    public Boolean checkToken(String token) {
        try {
            byte[] raw = authenticationProperties.getAesKey().getBytes("utf-8");
            SecretKeySpec secretKeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
            byte[] base64 = new Base64().decode(URLDecoder.decode(token, "utf-8"));
            byte[] original = cipher.doFinal(base64);
            String randomNumberWithUnixTime = new String(original, "utf-8");
            if (randomNumberWithUnixTime.length() > UNIX_TIME_LENGTH){
                long tokenUnixTime = Long.parseLong(randomNumberWithUnixTime.substring(randomNumberWithUnixTime.length() - UNIX_TIME_LENGTH, randomNumberWithUnixTime.length()));
                return (System.currentTimeMillis() - tokenUnixTime) < authenticationProperties.getExpire();
            }
        } catch (Exception e) {
            log.warn("token aes to session error: {}", LogUtil.getExceptionMessage(e));
        }
        return Boolean.FALSE;
    }
}